using System;
using System.Collections.Generic;
using System.Text;
using PandoraCommon;
using System.Windows.Forms;
using System.Threading;
using System.Globalization;
using System.IO;

namespace MiniLap
{
    /// <summary>
    /// Log reader for the output of the GPS based I2M MiniLap lap timer (www.i2m.it)
    /// </summary>
    public class LogReader : ILogReader
    {
        #region ILogReader Members

        /// <summary>
        /// Name of the log reader plug-in.
        /// </summary>
        /// <value></value>
        public string Name
        {
            get { return "I2M MiniLap log reader"; }
        }

        /// <summary>
        /// Description for the log reader plug-in.
        /// </summary>
        /// <value></value>
        public string Description
        {
            get { return "Log reader for the output of the GPS based I2M MiniLap lap timer (www.i2m.it)"; }
        }

        /// <summary>
        /// Author of this log reader plug-in.
        /// </summary>
        /// <value></value>
        public string Author
        {
            get { return "2008 (c) Mario Sobral"; }
        }

        /// <summary>
        /// Reads the necessary GPS position information from its associated positions source (file, database, GPS unit, etc...)
        /// and generates a list of <see cref="T:GpsPosition"> to be processed by the Pandora software.</see>
        /// </summary>
        /// <returns>A list of <see cref="T:GpsPosition"/></returns>
        public List<GpsPosition> ReadLog()
        {
            List<GpsPosition> positions = new List<GpsPosition>();

            OpenFileDialog openLogFileDialog = new OpenFileDialog();
            openLogFileDialog.CheckFileExists = true;
            openLogFileDialog.CheckPathExists = true;
            openLogFileDialog.DefaultExt = "txt";
            openLogFileDialog.FileName = "*.txt";
            openLogFileDialog.Filter = "I2M Mini Lap log files (*.txt)|*.txt";
            openLogFileDialog.InitialDirectory = Application.ExecutablePath;
            openLogFileDialog.Multiselect = false;
            openLogFileDialog.Title = "Select the I2M Mini Lap log file to read";
            if (openLogFileDialog.ShowDialog() == DialogResult.OK)
            {
                CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
                TextReader logFileReader = new StreamReader(openLogFileDialog.FileName);
                GpsPosition currentPosition;
                GpsPosition previousPosition = null;
                string newLine = string.Empty;
                

                try
                {
                    // read until a new session data is found 
                    while(newLine.ToUpper().Trim() != "$NEW SESSION")
                        newLine = logFileReader.ReadLine();

                    while(newLine.IndexOf("$DATE") == -1)
                        newLine = logFileReader.ReadLine();

                    string[] dateParameters = newLine.Split(',');
                    DateTime sessionDate = new DateTime(2000 + int.Parse(dateParameters[1].Substring(4,2)), 
                                                        int.Parse(dateParameters[1].Substring(2,2)), 
                                                        int.Parse(dateParameters[1].Substring(0,2)));

                    newLine = logFileReader.ReadLine();
                    while (newLine.IndexOf("$GPS,") != -1)
                    {
                        string[] positionParameters = newLine.Split(',');

                        GpsPosition newPosition = ExtractPositionData(positionParameters, sessionDate);
                        ProcessSensorData(positionParameters, sessionDate);
                        positions.Add(newPosition);

                        newLine = logFileReader.ReadLine();
                    }


                }
                catch(Exception ex)
                {
                    string errorMessage = "Error reading I2M Mini Lap data file!" + Environment.NewLine + Environment.NewLine;
                    if (newLine != string.Empty)
                        errorMessage += "Problem in data line: " + newLine + Environment.NewLine + Environment.NewLine;
                    errorMessage += ex.Message + Environment.NewLine + Environment.NewLine + "Stack trace: " + ex.StackTrace;
                    
                    MessageBox.Show(errorMessage);
                }
                finally
                {
                    Thread.CurrentThread.CurrentCulture = currentCulture;
                    if(logFileReader != null)
                        logFileReader.Close();
                }
            }

            MessageBox.Show(positions.Count.ToString() + " position(s) read from " + openLogFileDialog.FileName, this.Name);

            return positions;
        }

        #endregion


        /// <summary>
        /// Extracts the position data from the line parameters.
        /// </summary>
        /// <param name="positionParameters">The position parameters.</param>
        /// <param name="date">The date.</param>
        /// <returns></returns>
        private GpsPosition ExtractPositionData(string[] positionParameters, DateTime date)
        {
            CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

            int hour = (int) Math.Truncate(double.Parse(positionParameters[8]) / 10000);
            int minute = (int) Math.Truncate((double.Parse(positionParameters[8]) - (hour*10000)) / 100);
            int seconds = (int) Math.Truncate(double.Parse(positionParameters[8]) - (hour * 10000) - (minute*100));

            DateTime positionDateTime = date.AddHours(hour);
            positionDateTime = positionDateTime.AddMinutes(minute);
            positionDateTime = positionDateTime.AddSeconds(seconds);

            double altitude = double.Parse(positionParameters[9]);
            double latitude = ParseLatitude(positionParameters[3], positionParameters[4]);
            double longitude = ParseLatitude(positionParameters[5], positionParameters[6]);
            double speed = double.Parse(positionParameters[7]);
            

            Thread.CurrentThread.CurrentCulture = currentCulture;

            GpsPosition newPosition = new GpsPosition(positionDateTime, latitude, longitude, altitude, 0, speed, "");
            
            return newPosition;
        }


        /// <summary>
        /// Parses the latitude into a double value.
        /// </summary>
        /// <param name="coordinateString">The coordinate string.</param>
        /// <param name="Hemisphere">The hemisphere.</param>
        /// <returns></returns>
        private double ParseLatitude(string coordinateString, string Hemisphere)
        {
            string[] coordinateParts = coordinateString.Split('.');

            double degrees = Math.Truncate(double.Parse(coordinateParts[0]) / 100);
            double minutes = ((double.Parse(coordinateString) / 100) - degrees) * 1.66666667;
            double coordinate = degrees + minutes;

            if (Hemisphere.ToUpper() == "S")
                coordinate = coordinate * -1;

            return coordinate;
        }


        /// <summary>
        /// Parses the longitude into a double value.
        /// </summary>
        /// <param name="coordinateString">The coordinate string.</param>
        /// <param name="Hemisphere">The hemisphere.</param>
        /// <returns></returns>
        private double ParseLongitude(string coordinateString, string Hemisphere)
        {
            string[] coordinateParts = coordinateString.Split('.');

            double degrees = Math.Truncate(double.Parse(coordinateParts[0]) / 100);
            double minutes = ((double.Parse(coordinateString) / 100) - degrees) * 1.66666667;
            double coordinate = degrees + minutes;

            if (Hemisphere.ToUpper() == "W")
                coordinate = coordinate * -1;

            return coordinate;
        }



        private void ProcessSensorData(string[] positionParameters, DateTime date)
        {
            int rpm = 0;
            int distanceTraveled = 0; // meters
            int ticks = 0; // in miliseconds
            double frontValue = 0.0; // suspension position ?
            double rearValue = 0.0; // suspension position ?
            double analog1 = 0.0; // analogue sensor 1
            double analog2 = 0.0; // analogue sensor 2

            
            if (!string.IsNullOrEmpty(positionParameters[1]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[1]))
                ticks = int.Parse(positionParameters[1]);
            
            if (!string.IsNullOrEmpty(positionParameters[2]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[2]))
                frontValue = double.Parse(positionParameters[2]);

            if (!string.IsNullOrEmpty(positionParameters[3]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[3]))
                rearValue = double.Parse(positionParameters[3]);

            if (!string.IsNullOrEmpty(positionParameters[4]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[4]))
                distanceTraveled = int.Parse(positionParameters[4]);

            if (!string.IsNullOrEmpty(positionParameters[6]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[6]))
                rpm = int.Parse(positionParameters[6]);

            if (!string.IsNullOrEmpty(positionParameters[9]) && Microsoft.VisualBasic.Information.IsNumeric(positionParameters[9]))
                analog1 = double.Parse(positionParameters[9]);
           

        }
        
    }

        
    
}
